package com.ruoyi.app.common

import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty

/**
 * @ClassName Result.java
 * @author fly
 * @version 1.0.0
 * @Description TODO
 * @createTime 2022年02月24日 16:44:00
 */
sealed class R

@ApiModel("统一返回参数")
data class Data<T>(
    @ApiModelProperty("状态") var status: Int = 200,
    @ApiModelProperty("信息") var msg: String? = null,
    @ApiModelProperty("数据") var data: T? = null
)

data class Page<T>(
    @ApiModelProperty("总记录数") var total: Long? = 0,
    @ApiModelProperty("列表数据") var rows: List<T>? = null,
)
@ApiModel("统一分页列表返回参数")
data class PageData<T>(
    @ApiModelProperty("分页数据") var data: Page<T>? = Page(),
    @ApiModelProperty("消息状态码") var status: Int? = 200,
    @ApiModelProperty("消息内容") var msg: String? = null
)

enum class Status(val code: Int, val msg: String) {
    SUCCESS(200, "操作成功"),
    FAIL(500, "操作失败")
}

object Ok : R() {
    operator fun invoke(msg: String) = Data(Status.SUCCESS.code, msg, "")
    operator fun <T> invoke(msg: String, data: T?): Data<T> = Data(Status.SUCCESS.code, msg, data)
    operator fun invoke(status: Status) = Data(status.code, status.msg, "")
    operator fun <T> invoke(status: Status, data: T?) = Data(status.code, status.msg, data)
    operator fun <T> invoke(status: Status? = null, action: () -> T?) = Data<T>().apply {
        status?.run {
            this@apply.status = code
            this@apply.msg = msg
        }
        data = action()
    }

    operator fun <P, T> invoke(status: Status? = null, param: P, action: (P) -> T?) = Data<T>().apply {
        status?.run {
            this@apply.status = code
            this@apply.msg = msg
        }
        data = action(param)
    }

    operator fun <T> invoke(result: Result<T>, msg: String?): Data<T>? = when {
        result.isSuccess -> Data<T>().apply {
            data = result.getOrNull()
            this.msg = msg
        }

        result.isFailure -> Data<T>().apply {
            this.msg = result.exceptionOrNull()?.message
            status = Status.FAIL.code
        }

        else -> null
    }
}

object Fail : R() {
    operator fun <T> invoke(msg: String): Data<T> = Data(status = Status.FAIL.code, msg, null)
    operator fun <T> invoke(code: Int, msg: String): Data<T> = Data(status = code, msg = msg, null)
    operator fun <T> invoke(status: Status): Data<T> = Data(status = status.code, msg = status.msg, null)
}
